using System;
using System.IO;
using System.Xml.Serialization;
using SimpleServiceBus.Messages.ControlMessages;

namespace SimpleServiceBus.Bus
{
    public enum MessagePriorities
    {
        Lowest = 0,
        VeryLow = 1,
        Low = 2,
        Normal = 3,
        AboveNormal = 4,
        High = 5,
        VeryHigh = 6,
        Highest = 7
    }


    /// <summary>
    /// An envelope used by SimpleServiceBus to package messages for transmission.
    /// </summary>
    /// <remarks>
    /// All messages sent and received by SimpleServiceBus are wrapped in this class. 
    /// More than one message can be bundled in the envelope to be transmitted or 
    /// received by the bus.
    /// </remarks>
    [Serializable]
    public class MessageEnvelope : IHeadersProvider
    {
        public const string CorrelationID_HeaderKey = "SSB_CorrelationID";
        public const string MessageID_HeaderKey = "SSB_MessageID";
        public const string Recoverable_HeaderKey = "SSB_Recoverable";
        public const string ReturnAddress_HeaderKey = "SSB_ReturnAddress";
        public const string RetryCount_HeaderKey = "SSB_RetryCount";
        public const string Priority_HeaderKey = "SSB_Priority";

        public MessageEnvelope()
        {
            Headers = new Headers();
            Priority = MessagePriorities.Normal;
            TimeToBeReceived = TimeSpan.MaxValue;
        }

        /// <summary>
        /// Gets/sets the identifier of this message bundle.
        /// </summary>
        public virtual string MessageID
        {
            get { return Headers.GetValue<string>(MessageID_HeaderKey); }
            set { Headers[MessageID_HeaderKey] = value; }
        }


        public MessagePriorities Priority
        {
            get { return (MessagePriorities)Headers.GetValue<int>(Priority_HeaderKey); }
            set { Headers[Priority_HeaderKey] = ((int)value).ToString(); }
        }

        /// <summary>
        /// Gets/sets the uniqe identifier of another message bundle
        /// this message bundle is associated with.
        /// </summary>
        public string CorrelationID
        {
            get { return Headers.GetValue<string>(CorrelationID_HeaderKey); }
            set { Headers[CorrelationID_HeaderKey] = value; }
        }

        /// <summary>
        /// Gets/sets the return address of the message bundle.
        /// </summary>
        public string ReturnAddress
        {
            get { return Headers.GetValue<string>(ReturnAddress_HeaderKey); }
            set { Headers[ReturnAddress_HeaderKey] = value; }
        }

        /// <summary>
        /// Gets/sets whether or not the message is supposed to
        /// be guaranteed deliverable.
        /// </summary>
        public bool Recoverable
        {
            get { return Headers.GetValue<bool>(Recoverable_HeaderKey); }
            set { Headers[Recoverable_HeaderKey] = value.ToString(); }
        }

        /// <summary>
        /// Gets/sets the maximum time limit in which the message bundle
        /// must be received.
        /// </summary>
        [XmlIgnore]
        public TimeSpan TimeToBeReceived { get; set; }

        /// <summary>
        /// Indicate if the message queue should keep failed messages (dead-letter)
        /// </summary>
        [XmlIgnore]
        public bool UseDeadLetterQueue { get; set; }

        /// <summary>
        /// The number of times this message has been retried. Used
        /// to determine when to send it to the poison letter queue.
        /// </summary>
        public int RetryCount
        {
            get { return Headers.GetValue<int>(RetryCount_HeaderKey); }
            set { Headers[RetryCount_HeaderKey] = value.ToString();}
        }


        [XmlIgnore]
        public object Body { get; set; }


        /// <summary>
        /// Gets/sets a stream to the body content of the message
        /// </summary>
        /// <remarks>
        /// Used for cases where we can't deserialize the contents.
        /// </remarks>
        [XmlIgnore]
        public byte[] Payload { get; set; }

        #region IHeadersProvider Members

        [XmlIgnore]
        public Headers Headers { get; set; }

        #endregion

        public virtual bool IsInitializationMessageFor(IMessageBus bus)
        {
            if (String.IsNullOrEmpty(ReturnAddress))
                return false;

            if (!ReturnAddress.Contains(bus.Endpoint.Metadata.ReturnAddress))
                return false;

            if (CorrelationID != null)
                return false;


            var em = Body as CompletionMessage;

            if (em == null)
                return false;

            return true;
        }

       
    }
}